package org.zizi.manager.impl;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.zizi.action.Action;
import org.zizi.action.ActionContext;
import org.zizi.action.ActionService;
import org.zizi.action.UserException;
import org.zizi.manager.Manager;
import org.zizi.manager.Managers;
import org.zizi.util.Options;

public class ActionManager implements Manager
{
	private static Logger log = Logger.getLogger(ActionManager.class);
	
	private Map<Class<? extends Action>, ActionMapping<?>> services = new HashMap<Class<? extends Action>, ActionMapping<?>>();
	
	public void initialize(Options options) throws Exception
	{
	}
	
	@SuppressWarnings("unchecked")
	public <T extends ActionService> void register(Class<T> service)
	{
		int modifier = service.getModifiers();
		if (Modifier.isAbstract(modifier) || Modifier.isInterface(modifier)) return;
		if (!ActionService.class.isAssignableFrom(service)) return;
		
		// get all public method
		for (Method method : service.getMethods())
		{
			Class<?>[] pp = method.getParameterTypes();
			if (pp.length != 1) continue;		//只能有一个参数
			
			Class<?> p = pp[0];
			if (!Action.class.isAssignableFrom(p)) continue;
			
			Class<?> r = method.getReturnType();
			if (!r.equals(Void.TYPE)) return;
			
			ActionMapping<T> am = new ActionMapping<T>(service, method);
			services.put((Class<? extends Action>)p, am);
			
			log.info("载入操作：" + p.getName());
		}
	}
	
	@SuppressWarnings("unchecked")
	public void execute(Action action, HttpServletRequest request, HttpServletResponse response) throws Exception
	{
		//set action context
		ActionContext context = new ActionContext();
		context.setSession(request.getSession());
		context.setRequest(request);
		context.setResponse(response);
		
		ActionMapping<? extends Action> am = (ActionMapping<? extends Action>)services.get(action.getClass());
		if (am == null) throw new UserException("操作未实现：" + action.getClass().getName());
		
		ActionContext.set(context);
		
		//do execute
		DaoManager dm = Managers.get(DaoManager.class);
		try
		{
			dm.begin();
			
			am.method.invoke(am.clazz.newInstance(), action);
			
			if (!ActionContext.get().isRollback())
			{
				dm.commit();
			}
		}
		catch (InvocationTargetException e)
		{
			Throwable ex = e.getCause();
			if (ex instanceof Exception) throw (Exception)ex;
			else throw e;
		}
		finally
		{
			dm.end();
		}
	}

	public void destory()
	{
	}
	
	//
	private static final class ActionMapping<T extends ActionService>
	{
		private Class<T> clazz;
		private Method method;
		
		public ActionMapping(Class<T> clazz, Method method)
		{
			this.clazz = clazz;
			this.method = method;
		}
	}
}
